// skeleton.js
const fs = require("fs");
const { JSDOM } = require("jsdom");
const { webcrypto } = require("crypto");

// 创建全局的日志记录系统
const log = {
  api: [],
  iframe: [],
  flush: function() {
    console.log("===== API 环境日志 =====");
    this.api.forEach(entry => console.log(`API::: ${entry}`));
    console.log("\n===== IFRAME 环境日志 =====");
    this.iframe.forEach(entry => console.log(`IFRAME::: ${entry}`));
    this.api = [];
    this.iframe = [];
  }
};



// ---- 1. 创建 parent (auto + orchestrate) 环境 ----
//
// 创建 API 环境
parentDom = new JSDOM(`<!DOCTYPE html><body></body>`, {
  runScripts: "dangerously",
  beforeParse(window) {
    // 在解析前注入代理
    window._log = log;
    window._env = 'API';
    
    const proxyCode = `
      // API 环境代理
      window._proxyObjects = ['window', 'document', 'location', 'navigator', 'history', 'screen', 'crypto'];
      
      window._createProxy = function(obj, name) {
        if (typeof obj !== 'object' && typeof obj !== 'function') return obj;
        
        return new Proxy(obj, {
          get(target, prop, receiver) {
            const propStr = String(prop);
            
            // 过滤掉Symbol属性和内部属性
            if (typeof prop === 'symbol' || propStr.startsWith('_') || propStr.includes('Symbol')) {
              return Reflect.get(target, prop, receiver);
            }
            
            const value = Reflect.get(target, prop, receiver);
            const valueType = value !== null ? typeof value : 'null';
            const propType = typeof prop;
            
            window._log.api.push(
              \`方法: get  | 对象: \${name} | 属性: \${propStr} | 属性类型: \${propType} | 值类型: \${valueType}\`
            );
            
            if (valueType === 'object' && value !== null) {
              // 避免递归代理内部对象
              if (name.includes('Symbol') || name.includes('impl')) {
                return value;
              }
              return window._createProxy(value, \`\${name}.\${propStr}\`);
            }
            return value;
          },
          set(target, prop, value, receiver) {
            const propStr = String(prop);
            
            // 过滤掉Symbol属性和内部属性
            if (typeof prop === 'symbol' || propStr.startsWith('_') || propStr.includes('Symbol')) {
              return Reflect.set(target, prop, value, receiver);
            }
            
            const valueType = value !== null ? typeof value : 'null';
            const propType = typeof prop;
            
            window._log.api.push(
              \`方法: set  | 对象: \${name} | 属性: \${propStr} | 属性类型: \${propType} | 值类型: \${valueType}\`
            );
            
            return Reflect.set(target, prop, value, receiver);
          },
          apply(target, thisArg, args) {
            const argStr = args.map(arg => {
              try {
                if (arg === null) return 'null';
                if (typeof arg === 'object') return '[对象]';
                return String(arg).slice(0, 50);
              } catch {
                return '[无法序列化]';
              }
            }).join(', ');
            
            window._log.api.push(
              \`方法: call | 对象: \${name} | 函数: \${target.name || '匿名'} | 参数: \${argStr}\`
            );
            
            return Reflect.apply(target, thisArg, args);
          }
        });
      };
      
      // 代理关键对象
      window._proxyObjects.forEach(name => {
        try {
          const obj = eval(name);
          if (obj) {
            eval(\`\${name} = window._createProxy(\${name}, '\${name}')\`);
            window._log.api.push(\`成功代理API对象: \${name}\`);
          }
        } catch (e) {
          window._log.api.push(\`代理API对象失败: \${name} - \${e.message}\`);
        }
      });
    `;
    
    window.eval(proxyCode);
  }
});
parentWindow = parentDom.window;
crypto = webcrypto;
document = parentWindow.document
// 模拟插入一个 script 节点
const scriptEl = document.createElement("script");
scriptEl.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback";
document.head.appendChild(scriptEl);
// 手动设置 currentScript（因为 jsdom 里不会自动维护）
Object.defineProperty(document, "currentScript", {
  get() {
    return scriptEl;
  }
});
if (!parentWindow.document.getElementById('cf-captcha')) {
  const el = parentWindow.document.createElement('div');
  el.id = 'cf-captcha';
  // 根据需要可模拟一些 class / style / dataset
  el.className = 'cf-turnstile';
  el.setAttribute('data-clf-widget', '1'); // 任意
  parentWindow.document.body.appendChild(el);
  console.log('[setup] parent created #cf-captcha');
}
location = parentWindow.location;
history = parentWindow.history
HTMLScriptElement = parentWindow.HTMLScriptElement;








//
// ---- 2. 创建 iframe (challenge 解混淆脚本) 环境 ----
//
iframeDom = new JSDOM(`<!DOCTYPE html><body></body>`, {
  runScripts: "dangerously",
  beforeParse(window) {
    // 在解析前注入代理
    window._log = log;
    window._env = 'IFRAME';
    
    const proxyCode = `
      // IFRAME 环境代理
      window._proxyObjects = ['window', 'document', 'location', 'navigator', 'history', 'screen', 'crypto'];
      
      window._createProxy = function(obj, name) {
        if (typeof obj !== 'object' && typeof obj !== 'function') return obj;
        
        return new Proxy(obj, {
          get(target, prop, receiver) {
            const propStr = String(prop);
            
            // 过滤掉Symbol属性和内部属性
            if (typeof prop === 'symbol' || propStr.startsWith('_') || propStr.includes('Symbol')) {
              return Reflect.get(target, prop, receiver);
            }
            
            const value = Reflect.get(target, prop, receiver);
            const valueType = value !== null ? typeof value : 'null';
            const propType = typeof prop;
            
            window._log.iframe.push(
              \`方法: get  | 对象: \${name} | 属性: \${propStr} | 属性类型: \${propType} | 值类型: \${valueType}\`
            );
            
            if (valueType === 'object' && value !== null) {
              // 避免递归代理内部对象
              if (name.includes('Symbol') || name.includes('impl')) {
                return value;
              }
              return window._createProxy(value, \`\${name}.\${propStr}\`);
            }
            return value;
          },
          set(target, prop, value, receiver) {
            const propStr = String(prop);
            
            // 过滤掉Symbol属性和内部属性
            if (typeof prop === 'symbol' || propStr.startsWith('_') || propStr.includes('Symbol')) {
              return Reflect.set(target, prop, value, receiver);
            }
            
            const valueType = value !== null ? typeof value : 'null';
            const propType = typeof prop;
            
            window._log.iframe.push(
              \`方法: set  | 对象: \${name} | 属性: \${propStr} | 属性类型: \${propType} | 值类型: \${valueType}\`
            );
            
            return Reflect.set(target, prop, value, receiver);
          },
          apply(target, thisArg, args) {
            const argStr = args.map(arg => {
              try {
                if (arg === null) return 'null';
                if (typeof arg === 'object') return '[对象]';
                return String(arg).slice(0, 50);
              } catch {
                return '[无法序列化]';
              }
            }).join(', ');
            
            window._log.iframe.push(
              \`方法: call | 对象: \${name} | 函数: \${target.name || '匿名'} | 参数: \${argStr}\`
            );
            
            return Reflect.apply(target, thisArg, args);
          }
        });
      };
      
      // 代理关键对象
      window._proxyObjects.forEach(name => {
        try {
          const obj = eval(name);
          if (obj) {
            eval(\`\${name} = window._createProxy(\${name}, '\${name}')\`);
            window._log.iframe.push(\`成功代理IFRAME对象: \${name}\`);
          }
        } catch (e) {
          window._log.iframe.push(\`代理IFRAME对象失败: \${name} - \${e.message}\`);
        }
      });
      
      // 特殊处理 postMessage
      const originalPostMessage = window.postMessage;
      window.postMessage = function(message, origin, transfer) {
        let msgStr = '';
        try {
          msgStr = typeof message === 'object' ? 
            JSON.stringify(message).slice(0, 100) + (JSON.stringify(message).length > 100 ? '...' : '') : 
            String(message);
        } catch {
          msgStr = '[无法序列化的消息]';
        }
        
        window._log.iframe.push(
          \`方法: post | 对象: window | 函数: postMessage | 消息: \${msgStr} | 目标源: \${origin}\`
        );
        
        return originalPostMessage.call(this, message, origin, transfer);
      };
    `;
    
    window.eval(proxyCode);
  }
});
iframeWindow = iframeDom.window;
// 在关键点打印日志
setInterval(() => {
  log.flush();
}, 2000); // 每2秒打印一次日志

// 在程序结束时打印所有日志
process.on('exit', () => {
  log.flush();
});


//
// ---- 3. 串起 parent <-> iframe 的 postMessage 通道 ----
//
parentWindow.postMessage = (msg, origin = "*") => {
  setImmediate(() => {
    iframeWindow.dispatchEvent(new iframeWindow.MessageEvent("message", {
      data: msg,
      origin,
      source: parentWindow,
    }));
  });
};
iframeWindow.postMessage = (msg, origin = "*") => {
  setImmediate(() => {
    parentWindow.dispatchEvent(new parentWindow.MessageEvent("message", {
      data: msg,
      origin,
      source: iframeWindow,
    }));
  });
};

// 观察消息
parentWindow.addEventListener("message", e => {
  console.log("📩 Parent 收到 message:", e.data);
});
iframeWindow.addEventListener("message", e => {
  console.log("📩 Iframe 收到 message:", e.data);
});

//
// ---- 4. 加载脚本 ----
//

// helper: eval 脚本到指定 window
function runScriptInWindow(window, filePath) {
  const code = fs.readFileSync(filePath, "utf8");
  window.eval(code);
};

// 1) 先跑 parent 的 auto+orchestrate
runScriptInWindow(parentWindow, "./api.js"); // 你整合好的 parent 脚本

// 2) 桥接层级
Object.defineProperty(iframeWindow, "parent", { value: parentWindow, writable: false });


// 3) 桥接 _cf_chl_opt
// if (!parentWindow._cf_chl_opt) parentWindow._cf_chl_opt = {};
// Object.defineProperty(iframeWindow, "_cf_chl_opt", {
//   configurable: true,
//   get() { return parentWindow._cf_chl_opt; },
//   set(v) { parentWindow._cf_chl_opt = v; }
// });
// // 可选：如果你知道马上会用到某个子键，先确保存在
// if (!parentWindow._cf_chl_opt.RNTle6) parentWindow._cf_chl_opt.RNTle6 = {};
iframeWindow._cf_chl_opt = parentWindow._cf_chl_opt

F = false

const origRender = parentWindow.turnstile?.render;
if (origRender) {
  parentWindow.turnstile.render = function (container, opts) {
    console.log("[turnstile.render] container =", container);
    // if (!opts || typeof opts.sitekey !== "string") {
    //   const sitekey = parentWindow._cf_chl_opt.chlApiSitekey;
    //   console.log("[patch] fixing missing sitekey, using =", sitekey);
    //   opts = { ...(opts || {}), sitekey };
    // }
  if (container instanceof parentWindow.HTMLDivElement && opts === undefined) {
    console.log("[skip] ignoring duplicate render on", container);
    return; // 直接不跑
  }
    if(F){
        return;
    }
    F = true;
    console.log("[turnstile.render] opts", opts);
    return origRender.call(this, container, opts);
  };
}



// 4) 再跑 iframe 的 challenge（解混淆）脚本
runScriptInWindow(iframeWindow, "./iframe.js");
